---
title: Turborepo 2.4
date: 2025/1/31
description: 'Experimental Boundaries, Terminal UI improvements, experimental Watch Mode caching, and more.'
tag: 'web development'
---

<h1 className="text-center">Turborepo 2.4</h1>

import { Authors } from '#components/authors';
import { Date } from '#components/blog/date';
import { Tabs, Tab } from 'fumadocs-ui/components/tabs';
import { Accordions, Accordion } from '#components/accordion';
import { ExperimentalBadge } from '#components/experimental-badge';
import { Kbd } from '#components/kbd';
import { Callout } from '#components/callout';

<Date>Friday, January 31st, 2025</Date>

<Authors authors={['nicholasyang', 'anthonyshew', 'chrisolszewski']} />

Turborepo 2.4 includes a number of improvements to enhance your repository:

- [**Boundaries <ExperimentalBadge>Experimental</ExperimentalBadge>**](#boundaries-experimental): A first look at Boundaries in Turborepo
- [**Terminal UI improvements**](#terminal-ui-improvements): Persistent preferences and new features
- [**Watch Mode caching <ExperimentalBadge>Experimental</ExperimentalBadge>**](#watch-mode-caching-experimental): Develop faster in Watch Mode
- [**Circular dependency recommendations**](#circular-dependency-recommendations): Adopt Turborepo in large repos more easily
- [**`schema.json` in `node_modules`**](#schemajson-in-node_modules): Versioned configuration validation from within your repository
- [**ESLint Flat Config support**](#eslint-flat-config-support): `eslint-config-turbo` and `eslint-plugin-turbo` updated for ESLint v9

Upgrade today by running `npx @turbo/codemod migrate` or get started with `npx create-turbo@latest`.

## Boundaries <ExperimentalBadge>Experimental</ExperimentalBadge>

Turborepo is built on top of package manager Workspaces, leaning on ecosystem conventions as a part of determining your repository's task caching. However, this requires that all developers in the repository know and adhere to those conventions.

We're introducing Boundaries, an experimental feature to catch places in the repository where these best practices aren't being followed. This makes caching safer, and ensures your repository is prepared to use future Turborepo features safely.

Try it today using:

```bash title="Terminal"
turbo boundaries
```

This early iteration of Boundaries includes finding two types of monorepo mistakes:

- Importing a file outside of the package's directory
- Importing a package that is not specified in dependencies

<Callout type="info" title="Boundaries RFC">
  We look forward to hearing your feedback on [the Boundaries
  RFC](https://github.com/vercel/turborepo/discussions/9435), which includes
  proposals for these built-in diagnostics as well as custom-built Boundaries.
</Callout>

To learn more, [visit the documentation](/docs/reference/boundaries).

## Terminal UI improvements

We've continued iterating on the terminal UI, originally released in [Turborepo 2.0](/blog/turbo-2-0).

### Persistent preferences

In previous versions of Turborepo, you would need to reset the terminal UI to your desired state every time you would run `turbo`. In Turborepo 2.4, we'll persist several of the UI selections that you've made, including:

- The task that you had previously selected will be pre-selected the next time you run `turbo`. Give your up and down arrow keys a rest.
- Task list visibility, as described below
- Task selection pinning, as described below

Together, persisting these preferences creates a more seamless experience across `turbo` invocations, restoring the UI to the state from the previous run of `turbo`.

### New keybinds

We've added more functionality to the terminal UI to make it easier to work with your tasks and logs.

- **<Kbd>h</Kbd> to toggle task list**: You're often focused on one of your tasks, so you don't need to see your task list, all the time. Press the <Kbd>h</Kbd> key to show and hide the task list. This feature is a persistent preference, as described above.
- **<Kbd>c</Kbd> to copy logs**: Once you've highlighted a set of logs with your mouse, press <Kbd>c</Kbd> to copy the logs to your system clipboard.
- **<Kbd>j</Kbd> and <Kbd>k</Kbd> to select tasks**: You can now use <Kbd>j</Kbd> and <Kbd>k</Kbd> in addition to <Kbd>↑</Kbd> and <Kbd>↓</Kbd> to cycle through the task list. Vim users rejoice.
- **<Kbd>p</Kbd> to pin the selected task**: Selecting a task sets a "pin", meaning it will continue to be selected as your tasks change states. You can release the pin (or pin the task you're hovering) by pressing <Kbd>p</Kbd>. This feature is a persistent preference, as described above.
- **<Kbd>u</Kbd> and <Kbd>d</Kbd> to scroll logs**: You can now press <Kbd>u</Kbd> to scroll your logs up and <Kbd>d</Kbd> to scroll your logs down.
- **<Kbd>m</Kbd> to learn more**: Pressing <Kbd>m</Kbd> will show a popup listing all of the available keybinds.

[Visit the documentation to learn more.](/docs/crafting-your-repository/developing-applications)

## Watch Mode caching <ExperimentalBadge>Experimental</ExperimentalBadge>

[Watch Mode](/docs/crafting-your-repository/developing-applications#watch-mode) is a monorepo-aware watcher that re-runs tasks according to your [Task Graph](/docs/core-concepts/package-and-task-graph#task-graph). This opens up brand new ways to work in monorepos by leveraging a single, global, dependency-aware watcher, rather than many smaller, less powerful watcher scripts.

In this release, we're adding caching as an experimental feature in Watch Mode. To activate it, use the `--experimental-write-cache` flag:

```bash title="Terminal"
turbo watch dev --experimental-write-cache
```

To learn more about Watch Mode, [visit the documentation](/docs/reference/watch).

## Circular dependency recommendations

Circular dependencies are loops in your package graph that create non-deterministic cycles in Turborepo's [Task Graph](/docs/core-concepts/package-and-task-graph#task-graph). However, if there is a loop in your task graph, Turborepo is unable to determine which task comes before which, since they both depend on each other.

While adopting Turborepo in your monorepo, you may find circular dependencies as Turborepo create a more sophisticated, faster Task Graph than your previous task runner. Previously, Turborepo would naively list all of the packages involved in the cycle or cycles that exist in the repository's [Package Graph](/docs/core-concepts/package-and-task-graph#package-graph). Now, Turborepo will include the dependency relationships that need to be broken up to get rid of the cycles in your graph.

Compare the before and after of the terminal printouts below:

<Tabs items={["After", "Before"]}>
<Tab value="After">

```txt title="Terminal"
  × Invalid package dependency graph:
  ╰─▶ Cyclic dependency detected:
  │     @repo/logger, blog, storefront, @repo/ui
  │     The cycle can be broken by removing any of these sets of dependencies:
  │     { @repo/ui -> @repo/logger, @repo/ui -> storefront }
  │     { @repo/logger -> @repo/ui, @repo/ui -> storefront }
  │
  ╰─▶   api, admin
        The cycle can be broken by removing any of these sets of dependencies:
        { admin -> api }
        { api -> admin }
```

</Tab>

<Tab value="Before">

```txt title="Terminal"
  × Invalid package dependency graph: Cyclic dependency detected:
  │     @repo/logger, storefront, @repo/ui, blog
  │     api, admin
  ╰─▶ Cyclic dependency detected:
        @repo/logger, storefront, @repo/ui, blog
        api, admin
```

</Tab>
</Tabs>

## `schema.json` in `node_modules`

A `schema.json` file provides auto-complete and validation in your editor for JSON files. We have a web-accessible version of the `schema.json` for `turbo.json` hosted at [`https://turborepo.com/schema.json`](https://turborepo.com/schema.json), but some developers prefer to get the file from `node_modules` to stay synced with the installed version of `turbo`.

Starting in this release, `schema.json` is available in `node_modules` once you've run your package manager's install command:

```json title="turbo.json"
{
  "$schema": "./node_modules/turbo/schema.json"
}
```

<Callout title="node_modules location">
  We recommend installing `turbo` at the root of your repository, so the path
  for the schema should point to `node_modules` at the root of your repository.
  In [Package Configurations](/docs/reference/package-configurations), you may
  need to use a path like `../../node_modules/turbo/schema.json`.
</Callout>

[Visit the documentation](/docs/getting-started/editor-integration#sourcing-from-node_modules) for more information.

## ESLint Flat Config support

Turborepo 2.4 introduces support for ESLint v9 in `eslint-config-turbo` and `eslint-plugin-turbo`, following the end-of life for ESLint v8 on October 5, 2024.

<Tabs items={["eslint-config-turbo", "eslint-plugin-turbo"]}>

<Tab value="eslint-config-turbo">

```ts title="./packages/eslint-config/index.js"
import turboConfig from 'eslint-config-turbo/flat';

export default [
  ...turboConfig,
  // Other configuration
];
```

</Tab>

<Tab value="eslint-plugin-turbo">

```ts title="./packages/eslint-config/index.js"
import turbo from 'eslint-plugin-turbo';

export default [
  {
    plugins: {
      turbo,
    },
    rules: {
      'turbo/no-undeclared-env-vars': 'error',
    },
  },
  // Other configuration
];
```

</Tab>

</Tabs>

The configuration and plugin remain backward compatible for those still using ESLint v8 to ensure a smooth transition.

For more information, [visit the documentation](/docs/reference/eslint-config-turbo).

## Other changes

<Accordions>
  <Accordion title="Features (5)">

    - feat(link): add `--yes` and `--scope` flags to `link`
    ([#9466](https://github.com/vercel/turborepo/pull/9466))
    - feat(prune): add `--use-gitignore` flag ([#9797](https://github.com/vercel/turborepo/pull/9797))
    - feat: remote cache upload timeout ([#9491](https://github.com/vercel/turborepo/pull/9491))
    - feat: update `eslint-config-turbo` to support ESLint Flat Config. ([#9502](https://github.com/vercel/turborepo/pull/9502))
    - feat: respect gitignore during turbo prune ([#9711](https://github.com/vercel/turborepo/pull/9711))

  </Accordion>
  <Accordion title="Fixes (29)">

    - fix(windows): fix env var glob casing ([#9429](https://github.com/vercel/turborepo/pull/9429))
    - fix(cache): allow force to override any cache settings ([#9454](https://github.com/vercel/turborepo/pull/9454))
    - fix(cache): no longer let remoteCache.enable override force ([#9684](https://github.com/vercel/turborepo/pull/9684))
    - fix(cache): suggest proper --cache flag for --remote-cache-read-only ([#9701](https://github.com/vercel/turborepo/pull/9701))
    - fix(cache): avoid warning if TURBO_FORCE, TURBO_REMOTE_ONLY, and TURBO_CACHE ([#9704](https://github.com/vercel/turborepo/pull/9704))
    - fix(affected): consider both source and destination as changed ([#9422](https://github.com/vercel/turborepo/pull/9422))
    - fix(env): add DISPLAY to default pass through ([#9511](https://github.com/vercel/turborepo/pull/9511))
    - fix(env): allow `passThroughEnv` to negate built ins and `globalPassThroughEnv` ([#9680](https://github.com/vercel/turborepo/pull/9680))
    - fix(cli): error on out of place run args ([#9445](https://github.com/vercel/turborepo/pull/9445))
    - fix(daemon): limit number of git children ([#9572](https://github.com/vercel/turborepo/pull/9572))
    - fix(examples): create-turbo dependencies with npm ([#9580](https://github.com/vercel/turborepo/pull/9580))
    - fix(examples): add missing ESLint dependency ([#9640](https://github.com/vercel/turborepo/pull/9640))
    - fix(examples): basic generator ([#9687](https://github.com/vercel/turborepo/pull/9687))
    - fix(examples): bug in design system example ([#9284](https://github.com/vercel/turborepo/pull/9284))
    - fix(example): remove conflict css property from with-tailwind example ([#9816](https://github.com/vercel/turborepo/pull/9816))
    - fix(berry): add yarn berry support for built dependencies meta when pruning ([#9605](https://github.com/vercel/turborepo/pull/9605))
    - fix(watch): watch command require tasks argument ([#9598](https://github.com/vercel/turborepo/pull/9598))
    - fix(watch): fix output text when no tasks are provided ([#9612](https://github.com/vercel/turborepo/pull/9612))
    - fix(watch): correctly derive opts from watch mode args ([#9761](https://github.com/vercel/turborepo/pull/9761))
    - fix(package-manager): allow custom URL for `packageManager` version ([#9624](https://github.com/vercel/turborepo/pull/9624))
    - fix(repository): honour handleTransparentWorkspaces setting in Yarn/Berry ([#9626](https://github.com/vercel/turborepo/pull/9626))
    - fix(prune): fix Yarn1 entries getting merged erroneously ([#9627](https://github.com/vercel/turborepo/pull/9627))
    - fix(create-turbo): correct repo name ([#9708](https://github.com/vercel/turborepo/pull/9708))
    - fix(tui): avoid zombie process on clipboard write failure ([#9713](https://github.com/vercel/turborepo/pull/9713))
    - fix(filewatcher): handle removed directories #8800 ([#9406](https://github.com/vercel/turborepo/pull/9406))
    - fix: correct TUI vim binds direction ([#9529](https://github.com/vercel/turborepo/pull/9529))
    - fix: packages listed twice in watch mode ([#9644](https://github.com/vercel/turborepo/pull/9644))
    - fix: respect output mode 'none' even when caching is disabled ([#9670](https://github.com/vercel/turborepo/pull/9670))
    - fix: upgrade the turbo package in Yarn 4 ([#8076](https://github.com/vercel/turborepo/pull/8076))

    </Accordion>
    <Accordion title="Documentation (42)">

    - docs: changesets configuration ([#9325](https://github.com/vercel/turborepo/pull/9325))
    - docs: clarify output globs relativeness. ([#9449](https://github.com/vercel/turborepo/pull/9449))
    - docs: add `TURBO_CACHE` to System Environment Variables. ([#9450](https://github.com/vercel/turborepo/pull/9450))
    - docs(turbopack): Add incremental-computation page, intended to replace core-concepts page ([#9456](https://github.com/vercel/turborepo/pull/9456))
    - docs(turbopack): Remove old core-concepts page ([#9457](https://github.com/vercel/turborepo/pull/9457))
    - docs: small stylistic change for footnote. ([#9451](https://github.com/vercel/turborepo/pull/9451))
    - docs: improve clarity on `--cache`. ([#9489](https://github.com/vercel/turborepo/pull/9489))
    - docs: mark `--no-cache` and `--remote-only` as deprecated. ([#9488](https://github.com/vercel/turborepo/pull/9488))
    - docs: describe using a custom URL with `create-turbo`. ([#9507](https://github.com/vercel/turborepo/pull/9507))
    - docs: fix formatting on `/docs/getting-started/installation` ([#9509](https://github.com/vercel/turborepo/pull/9509))
    - docs: fix formatting on `/docs/getting-started/installation` ([#9514](https://github.com/vercel/turborepo/pull/9514))
    - docs: update ESLint documentation with ESLint v9 ([#9515](https://github.com/vercel/turborepo/pull/9515))
    - docs: options one-pager ([#9533](https://github.com/vercel/turborepo/pull/9533))
    - docs(typo): fix typo on turbo-ignore page ([#9576](https://github.com/vercel/turborepo/pull/9576))
    - docs: clarify default daemon usage ([#9566](https://github.com/vercel/turborepo/pull/9566))
    - docs: provide reasoning on why Turborepo doesn't support nested workspaces ([#9586](https://github.com/vercel/turborepo/pull/9586))
    - docs: update CONTRIBUTING.md ([#9590](https://github.com/vercel/turborepo/pull/9590))
    - docs: change path of options overview page ([#9600](https://github.com/vercel/turborepo/pull/9600))
    - docs: remove old options page ([#9601](https://github.com/vercel/turborepo/pull/9601))
    - docs: add community implementations of Remote Cache ([#9631](https://github.com/vercel/turborepo/pull/9631))
    - docs: fix CONTRIBUTING.md typo ([#9637](https://github.com/vercel/turborepo/pull/9637))
    - docs: mention capnp in the dependencies ([#9643](https://github.com/vercel/turborepo/pull/9643))
    - docs: add missing `api` folder in `turbo prune api --docker` example ([#9648](https://github.com/vercel/turborepo/pull/9648))
    - docs: add missing `apps` folder in `prune` command reference ([#9658](https://github.com/vercel/turborepo/pull/9658))
    - docs: correct Bun support status ([#9664](https://github.com/vercel/turborepo/pull/9664))
    - docs: mention module resolution differences for package managers ([#9665](https://github.com/vercel/turborepo/pull/9665))
    - docs(errors): improve error message for recursive calls ([#9650](https://github.com/vercel/turborepo/pull/9650))
    - docs: guide for Playwright ([#9662](https://github.com/vercel/turborepo/pull/9662))
    - docs: mention --graph on graphs page ([#9661](https://github.com/vercel/turborepo/pull/9661))
    - docs: document creating packages with framework bindings ([#9222](https://github.com/vercel/turborepo/pull/9222))
    - docs: add note about packaging patterns ([#9673](https://github.com/vercel/turborepo/pull/9673))
    - docs: guide for shadcn/ui ([#9675](https://github.com/vercel/turborepo/pull/9675))
    - docs: add link to shadcn/ui page ([#9678](https://github.com/vercel/turborepo/pull/9678))
    - docs: mention free remote caching earlier on page ([#9688](https://github.com/vercel/turborepo/pull/9688))
    - docs: typo fix ([#9690](https://github.com/vercel/turborepo/pull/9690))
    - docs(fix): correct line highlighting by removing extra comma ([#9696](https://github.com/vercel/turborepo/pull/9696))
    - docs: add community-built Run Summaries web viewer ([#9679](https://github.com/vercel/turborepo/pull/9679))
    - docs: edits for Prisma guide ([#9682](https://github.com/vercel/turborepo/pull/9682))
    - docs: update docs to use correct changeset dir ([#9722](https://github.com/vercel/turborepo/pull/9722))
    - docs: update CONTRIBUTING.md ([#9759](https://github.com/vercel/turborepo/pull/9759))
    - docs: migration guide for users coming from Nx ([#9762](https://github.com/vercel/turborepo/pull/9762))
    - docs: fix typo ([#9814](https://github.com/vercel/turborepo/pull/9814))

    </Accordion>

</Accordions>

## Acknowledgments and community

Turborepo is the result of the combined work of all of its contributors, including our core team: [Anthony](https://github.com/anthonyshew), [Chris](https://github.com/chris-olszewski), [Dimitri](https://github.com/dimitropoulos), [Nicholas](https://github.com/NicholasLYang), and [Tom](https://github.com/tknickman).

Thank you for your continued support, feedback, and collaboration to make Turborepo your build tool of choice. To learn how to get involved, [visit the Community page](/docs/community).

We also thank everyone who contributed to this release of Turborepo: @aaronccasanova, @AlvaroParker, @ankur-arch, @arosequist, @atimmer, @bgw, @bitttttten, @chaficnajjar, @codexshell, @eps1lon, @gianelli99, @glitched-w0rld, @JasonnnW3000, @jbrocksfellas, @jeremy-code, @jonathandsouza, @Juneezee, @kayumuzzaman, @krlvi, @maciej-ka, @ognevny, @olets, @pkerschbaum, @romanofski, @shivam-pawar, @takaebato, @tevem1207, @thebrubaker, @Tofandel, @trivikr, @yamz8, and @zsh77.
